(function($) {	
	//所有的工具条按钮.
	var allToolbarItems  = {
		bold : {				
			tags : ['b', 'strong'],
			css : {
				fontWeight : 'bold'
			},
			tooltip : "Bold"
		},
		italic : {
			tags : ['i', 'em'],
			css : {
				fontStyle : 'italic'
			},
			tooltip : "Italic"
		},
		strikeThrough : {				
			tags : ['s', 'strike'],
			css : {
				textDecoration : 'line-through'
			},
			tooltip : "Strike-through"
		},
		underline : {
			tags : ['u'],
			css : {
				textDecoration : 'underline'
			},
			tooltip : "Underline"
		},
		//---------------------------------------
		separator00 : {			
			separator : true
		},
		//---------------------------------------
		justifyLeft : {				
			css : {
				textAlign : 'left'
			},
			tooltip : "Justify Left"
		},
		justifyCenter : {				
			tags : ['center'],
			css : {
				textAlign : 'center'
			},
			tooltip : "Justify Center"
		},
		justifyRight : {				
			css : {
				textAlign : 'right'
			},
			tooltip : "Justify Right"
		},
		justifyFull : {				
			css : {
				textAlign : 'justify'
			},
			tooltip : "Justify Full"
		},
		//---------------------------------------
		separator01 : {				
			separator : true
		},
		//---------------------------------------
		indent : {				
			tooltip : "Indent"
		},
		outdent : {				
			tooltip : "Outdent"
		},
		//---------------------------------------
		separator02 : {				
			separator : true
		},
		//---------------------------------------
		subscript : {				
			tags : ['sub'],
			tooltip : "Subscript"
		},
		superscript : {				
			tags : ['sup'],
			tooltip : "Superscript"
		},
		//---------------------------------------
		separator03 : {			
			separator : true
		},
		//---------------------------------------
		undo : {				
			tooltip : "Undo"
		},
		redo : {				
			tooltip : "Redo"
		},
		//---------------------------------------
		separator04 : {				
			separator : true
		},
		//---------------------------------------
		insertOrderedList : {				
			tags : ['ol'],
			tooltip : "Insert Ordered List"
		},
		insertUnorderedList : {				
			tags : ['ul'],
			tooltip : "Insert Unordered List"
		},
		insertHorizontalRule : {				
			tags : ['hr'],
			tooltip : "Insert Horizontal Rule"
		},
		//---------------------------------------
		separator05 : {
			separator : true
		},
		//---------------------------------------
		createLink : {				
			exec : function() {
				var selection = $.getSelectionText(this.editor);
				if(selection.length > 0) {						
					var url = prompt('URL', 'http://');
					if( url && url.length > 0 ) {
						this.editorDoc.execCommand('unlink', false, []);
						this.editorDoc.execCommand('createLink', false, url);
					}						
				} else {
					alert(this.options.messages.nonSelection);
				}
			},
			tags : ['a'],
			tooltip : "Create link"
		},
		insertImage : {
			visible : true,
			exec : function() {					
				var url = prompt('URL', 'http://');
				if(url && url.length > 0){
					this.editorDoc.execCommand('insertImage', false, url);
				}					
			},
			tags : ['img'],
			tooltip : "Insert image"
		},
		insertAnotation : {			
			exec : function() {
				var annotationID = Date.tick();
				this.editorDoc.execCommand(
					'insertHTML', 
					false, 
					'<img id="{0}" class="annotationAnchor" src="{1}"/>'.format(annotationID, ujs.getRes('images/common16/annotation.png'))
				);
				var annotationDialog = this.getAnotationDialog();
				annotationDialog.annotationID = annotationID;
				annotationDialog.show();		
			},
			tags : ['img'],
			tooltip : "Insert Anotation"
		},
		insertTable : {
			className : 'insertTable',
			customFun : function($menuItem){
				var _this = this;
				$menuItem.bind('mouseover',function(){
					var $tableSelector = $menuItem.find('.tableSelectorWrapper');
					if(!$tableSelector.length){	
						$menuItem.css('position', 'relative').css('width', '20px');
						$tableSelector = $([
							'<div class="tableSelectorWrapper">',
								'<h3 class="tableSelectorTitle">Insert Table</h3>',
								'<div class="tableSelectorTable">',
									'<table></table>',
								'</div>',
							'</div>'
						].join(''));
						
						var rowCount = 6,
							columnCount = 8,							
							i,
							j,							
							$tableSelectorTable = $tableSelector.find('table'),
							
							showTableDimension = function(rowCount, columnCount){
								var $tableSelectorTitle = $tableSelector.find('.tableSelectorTitle'); 
								if(!rowCount){
									$tableSelectorTitle.html('Insert Table');
								} else {
									$tableSelectorTitle.html('{0} rows {1} columns'.format(rowCount, columnCount));
								}
							};
						
						for(i=0; i<rowCount; i++){
							var $newRow = $('<tr></tr>').appendTo($tableSelectorTable);
							for(j=0; j<columnCount; j++){
								$('<td><td>').appendTo($newRow);
							}
						}
						
						$tableSelectorTable.delegate('td', 'mouseover', function(){
							
							var rowCount = $(this).parents('tr').index() + 1,
								columnCount = $(this).index() + 1;
								
							$tableSelectorTable
								.find('tr:lt({0})'.format(rowCount))
								.find('td:lt({0})'.format(columnCount))
								.addClass('selected');
							
							$tableSelectorTable
								.find('tr:gt({0})'.format(rowCount-1))
								.find('td:gt({0})'.format(columnCount-1))
								.removeClass('selected');
								
							showTableDimension(rowCount, columnCount);
															
						}).delegate('td', 'click', function(){
							var rowCount = $(this).parents('tr').index() + 1,
								columnCount = $(this).index() + 1,
								
								i,
								j;
							
							var tableHTML = ['<table class="insertedTable">'];
							for(i=0; i<rowCount; i++){
								tableHTML.push('<tr>');
								for(j=0; j<columnCount; j++){
									tableHTML.push('<td>&nbsp;</td>');
								}
								tableHTML.push('</tr>');
							}
							tableHTML.push('</table>');
							
							_this.editorDoc.execCommand('insertHTML', false, tableHTML.join(''));
							
							$tableSelector.hide();	
							
						}).bind('mouseout', function(){
							$(this).find('td').removeClass('selected');
							showTableDimension();
						});
						
						$menuItem.append($tableSelector);
					} else {
						$tableSelector.show();
					}
				}).bind('mouseout', function(){
					$menuItem.find('.tableSelectorWrapper').hide();
				});			
			}
		},
		//---------------------------------------
		separator06 : {
			separator : true
		},
		//---------------------------------------			
		h1 : {				
			className : 'h1',
			command : 'formatBlock',
			arguments : ['<H1>'],
			tags : ['h1'],
			tooltip : "Header 1"
		},
		h2 : {
			className : 'h2',
			command : 'formatBlock',
			arguments : ['<H2>'],
			tags : ['h2'],
			tooltip : "Header 2"
		},
		h3 : {
			className : 'h3',
			command : 'formatBlock',
			arguments : ['<H3>'],
			tags : ['h3'],
			tooltip : "Header 3"
		},
		//---------------------------------------
		separator07 : {
			separator : true
		},
		//---------------------------------------
		cut : {			
			tooltip : "Cut"
		},
		copy : {
			tooltip : "Copy"
		},
		paste : {
			tooltip : "Paste"
		},
		//---------------------------------------
		separator08 : {
			separator : true
		},
		//---------------------------------------
		increaseFontSize : {
			tags : ['big'],
			tooltip : "Increase font size"
		},
		decreaseFontSize : {
			tags : ['small'],
			tooltip : "Decrease font size"
		},
		//---------------------------------------
		separator09 : {
			separator : true
		},
		//---------------------------------------
		removeFormat : {
			exec : function() {					
				this.editorDoc.execCommand('removeFormat', false, []);
				this.editorDoc.execCommand('unlink', false, []);
			},
			tooltip : "Remove formatting"
		},
		//---------------------------------------
		html : {
			exec : function() {
				if(this.viewHTML) {
					this.setContent( $(this.original).val() );
					$(this.original).hide();
				} else {
					this.saveContent();
					$(this.original).show();
				}
				this.viewHTML = !this.viewHTML;
			},
			tooltip : "View source code"
		}		
	}, 
	//精简后的工具条按钮.
	simplifiedToolbarItems = {								
		separator00 : {	visible : false },								
		justifyLeft : { visible : false },
		justifyCenter : { visible : false },
		justifyRight : { visible : false },
		justifyFull : { visible : false },
		separator01 : { visible : false },
		indent : { visible : false },
		outdent : { visible : false },
		separator02 : { visible : false }, 
		insertAnotation : { visible : false },
		insertTable : { visible : false },
		h1 :  { visible : false },
		h2 : { visible : false },
		h3 : { visible : false },
		separator07 : { visible : false },
		increaseFontSize : { visible : false },
		decreaseFontSize : { visible : false },
		separator09 : { visible : false },
		html : { visible : false },
		removeFormat : { visible : false }
	},
	MSGS = {
		nonSelection : 'select the text you wish to link'
	};
	
	//------------------------------------------------------------------------------------------------
	
	$.fn.wysiwyg = function(options) {
		if(arguments.length > 0 && arguments[0].constructor == String) {
			var action = arguments[0].toString(),
				params = [];
				i,
				argsLen;
				
			for( i = 1, argsLen = arguments.length; i < argsLen; i++ ){
				params[i - 1] = arguments[i];
			}

			if( action in Wysiwyg) {
				return this.each(function() {
					$.data(this, 'wysiwyg').designMode();
					Wysiwyg[action].apply(this, params);
				});
			} else {
				return this;
			}
		}

		var toolbarItems = {};

		/**
		 * If the user set custom toolbarItems, we catch it, and merge with the
		 * defaults toolbarItems later.
		 */
		if(options && options.toolbarItems) {
			toolbarItems = options.toolbarItems;
			delete options.toolbarItems;
		}
		options = $.extend({
			html : [
				'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">',
					'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">',
					'<link type="text/css" rel="stylesheet" href="/res/css/wysiwyg.css">',					
					'<head>',
						'<script src="/res/js/common/jquery/base/jquery-1.8.2.min.js"></script>',						
					'</head>',
					'<body style="margin: 0px;">INITIAL_CONTENT</body>',										
				'</html>'
			].join(''),
			
			css : {},

			debug : false,

			autoSave : true, // http://code.google.com/p/jwysiwyg/issues/detail?id=11
			rmUnwantedBr : true, // http://code.google.com/p/jwysiwyg/issues/detail?id=15
			brIE : true,

			toolbarItems : {},
			messages : {}
			
		}, options);

		options.messages = $.extend(true, options.messages, MSGS);
		options.toolbarItems = $.extend(true, options.toolbarItems, allToolbarItems);

		for(var toolbarItem in toolbarItems ) {
			if( toolbarItem in options.toolbarItems){
				$.extend(options.toolbarItems[toolbarItem], toolbarItems[toolbarItem]);
			} else {
				options.toolbarItems[toolbarItem] = toolbarItems[toolbarItem];
			}
		}

		// not break the chain
		return this.each(function() {		    
		    $(this).data('wysiwyg', Wysiwyg(this, options));		
		});
	};
	
	//--------------------------------------------------------------------------------------------------
	
	//Editor构造函数.
	function Wysiwyg(element, options) {
		return this instanceof Wysiwyg ? this.init(element, options) : new Wysiwyg(element, options);
	}

	//--------------------------------------------------------------------------------------------------

	$.extend(Wysiwyg, {		
		insertImage : function(url, attributes) {
			var self = $.data(this, 'wysiwyg');
			if(self.constructor == Wysiwyg && url && url.length > 0) {				
				if(attributes) {
					self.editorDoc.execCommand('insertImage', false, '#wysiwyg#');
					var img = $.getElementByAttributeValue('img', 'src', '#wysiwyg#');
					if( img ) {
						img.src = url;
						for(var attribute in attributes ) {
							img.setAttribute(attribute, attributes[attribute]);
						}
					}
				} else {
					self.editorDoc.execCommand('insertImage', false, url);
				}
			}
		},		
		createLink : function(url) {
			var self = $.data(this, 'wysiwyg');
			if(self.constructor == Wysiwyg && url && url.length > 0) {
				var selection = $.getSelectionText(self.editor);
				if(selection.length > 0) {					
					self.editorDoc.execCommand('unlink', false, []);
					self.editorDoc.execCommand('createLink', false, url);
				} else {
					alert(self.options.messages.nonSelection);
				}
			}
		},		
		insertHtml : function(html) {
			var self = $.data(this, 'wysiwyg');
			if(self.constructor == Wysiwyg && html && html.length > 0) {				
				self.editorDoc.execCommand('insertHTML', false, html);
			}
		},		
		setContent : function(newContent) {
			var self = $.data(this, 'wysiwyg');
			self.setContent(newContent);
			self.saveContent();
		},		
		clear : function() {
			var self = $.data(this, 'wysiwyg');
			self.setContent('');
			self.saveContent();
		}		
	});
	
	//--------------------------------------------------------------------------------------------------

	$.extend(Wysiwyg.prototype, {				
		init : function(element, options) {
			
			//将editor实例，暂时存储于element.
			$.data(element, 'wysiwyg', this);
			
			this.options = options || {};
			this.original = $(element);

			var self = this,
				editorWidth = this.options['width'] || element.width || element.clientWidth || element.style.width,
				editorHeight = this.options['height'] || element.height || element.clientHeight || element.style.height;
				
			editorHeight = ( typeof editorHeight === 'number' ) ? editorHeight + 'px' : editorHeight;
			editorWidth = ( typeof editorWidth === 'number' ) ? editorWidth + 'px' : editorWidth;
			this.initialHeight = editorHeight;
			
			this.toolbar = $('<ul role="menu" class="panel"></ul>');	
			this.appendToolbarItems();
						
			this.editor = $('<iframe src="javascript:false;"></iframe>')
				.css({
					height : editorHeight,
					width : editorWidth 
				})
				.attr('id', this.original.attr('id') + '_IFrame')
				.attr('frameborder', '0')
				.attr('tabindex', this.original.attr('tabindex'));
						
			this.editorWrapper = $('<div></div>')
				.css({ width : editorWidth })
				.addClass('wysiwyg')
				.append(this.toolbar)
				.append( $('<div><!-- --></div>').css({ clear : 'both' }) )
				.append(this.editor);

			this.original.hide().before(this.editorWrapper);

			this.initialContent = this.original.val();
			if(this.initialContent.length == 0){
				this.setContent('');
			}

			this.viewHTML = false;
			
			this.initFrame();
			
			var relatedForm = $(element).closest('form');
			if(this.options.autoSave) {
				relatedForm.submit(function() {
					self.saveContent();
				});
			}
			relatedForm.bind('reset', function() {
				self.setContent(self.initialContent);
				self.saveContent();
			});
		},
		initFrame : function() {
			var self = this;
			
			var style = '';			
			if( this.options.css && this.options.css.constructor == String ) {
				style = '<link rel="stylesheet" type="text/css" media="screen" href="{0}" />'.format(this.options.css);
			}
			
			this.editorDoc = $.getDocument(this.editor);
			this.editorDoc.open();
			this.editorDoc.write(
				this.options.html
					.replace( /INITIAL_CONTENT/, function() {
						return self.initialContent;
					}).replace( /STYLE_SHEET/, function() {
						return style;
					})
			);
			this.editorDoc.close();	
			
			self.designMode();	
			
			$(this.editorDoc).click(function(event) {
				self.checkTargets(event.target || event.srcElement);
			});	
		},		
		focus : function() {
			$(this.editorDoc.body).focus();
		},				
		setWidth : function(width){
			if( width ){
				this.editor.add( this.editorWrapper ).css('width', width + 'px');
			}
		},		
		setHeight : function(height){
			if( height ){
				this.editor.css('height', height + 'px');
			}
		},
		designMode : function() {			
			if( !this.editorDoc_designMode ) {
				try {
					this.editorDoc.contentEditable = 'true';
					this.editorDoc.designMode = 'on';					
					this.editorDoc_designMode = true;
				} catch ( e ) {}
			}
		},		
		getRange : function() {			
			var selection = $.getSelectionText(this.editor);
			if( !selection ){
				return null;
			}
			return ( selection.rangeCount > 0 ) ? selection.getRangeAt(0) : selection.createRange();
		},
		getContent : function() {
			return $($.getDocument(this.editor)).find('body').html();
		},
		getText : function() {
			return $($.getDocument(this.editor)).find('body').text();
		},
		setContent : function(newContent) {
			$($.getDocument(this.editor)).find('body').html(newContent);
		},
		saveContent : function() {
			if(this.original) {
				var content = this.getContent();
				if(this.options.rmUnwantedBr) {
					content = (content.substr(-4) == '<br>' ) ? content.substr(0, content.length - 4) : content;
				}
				$(this.original).val(content);
			}
		},
		withoutCss : function() {
			if($.browser.mozilla) {
				try {
					this.editorDoc.execCommand('styleWithCSS', false, false);
				} catch (e) {
					try {
						this.editorDoc.execCommand('useCSS', false, true);
					} catch (e) { }
				}
			}
		},
		appendMenu : function(cmd, args, className, fn, tooltip, customFun) {
			var self = this;
			var menuItem = $('<li></li>').append(
				$('<a role="menuitem" tabindex="-1" href="javascript:false;">{0}</a>'.format( cmd ))
					.addClass(className)
					.attr('title', tooltip)
			).click(function() {
				if( fn ){
					fn.apply(self);
				} else {
					self.withoutCss();
					self.editorDoc.execCommand(cmd, false, args);
				}
				if(self.options.autoSave){
					self.saveContent();
				}
			}).appendTo(this.toolbar);
			
			customFun && customFun.call(self, menuItem);
		},
		appendMenuSeparator : function() {
			$('<li role="separator" class="separator"></li>').appendTo(this.toolbar);
		},
		appendToolbarItems : function() {
			for(var name in this.options.toolbarItems ) {
				var toolbarItem = this.options.toolbarItems[name];
				if(toolbarItem.visible !== false){
					if(toolbarItem.separator) {					
						this.appendMenuSeparator();					
					} else {
						this.appendMenu(
							toolbarItem.command || name, 
							toolbarItem.arguments || [], 
							toolbarItem.className || toolbarItem.command || name || 'empty', 
							toolbarItem.exec, 
							toolbarItem.tooltip || toolbarItem.command || name || '',
							toolbarItem.customFun
						);
					}
				}
			}
		},
		checkTargets : function(element) {			
			for(var name in this.options.toolbarItems ) {
				var toolbarItem = this.options.toolbarItems[name],
					className = toolbarItem.className || toolbarItem.command || name || 'empty',
					$toolbarItem = $( '.' + className, this.toolbar ); 

				$toolbarItem.removeClass('active');

				if(toolbarItem.tags) {
					var elm = element;
					do {	
						if( elm.nodeType === 1 && $.inArray( elm.tagName.toLowerCase(), toolbarItem.tags ) != -1 ){
							$toolbarItem.addClass('active');
						}					
					} while ( elm = elm.parentNode );
				}

				if(toolbarItem.css) {
					var elm = $(element);
					if(elm.nodeType === 1){
						do {						
							for(var cssProperty in toolbarItem.css ){
								if( elm.css(cssProperty).toString().toLowerCase() == toolbarItem.css[cssProperty] ){
									$toolbarItem.addClass('active');
								}
							}					
						} while ( elm = elm.parent() );
					}
				}
			}
		},
		getAnotationDialog : function(){
			var _this = this;
			if( true ){ //!this.__annotationDialog){
				this.__annotationDialog = new ujs.ui.Dialog({
					title : 'Edit Anotation',
					icon : ujs.getRes('images/common32/annotation.png')
				});
				this.__annotationDialog.addDialogContent(
					'<textarea style="width:500px;height:170px"></textarea>',
					function($editor){
						$editor.wysiwyg({
							toolbarItems : simplifiedToolbarItems 
						});
					}
				);
				this.__annotationDialog.addDialogButton([
					{					
						cls : 'submit',		
						text : 'Submit',
						handler : function($btnObj){							
							var annotationDialog = _this.__annotationDialog,
								annotationEditor = $.data(annotationDialog.dialogBody.find('textarea')[0],'wysiwyg');
																			
							$(_this.editorDoc).find('#'+annotationDialog.annotationID)[0].insertAdjacentHTML('AfterEnd', [
								'<div contenteditable="false" class="annotationWrapper">',
									'<div id="a-{0}" annotationID="{0}" class="annotationSummary">{1}</div>',
									'<div class="annotationContent">{2}</div>',
								'</div>'	
							].join('').format(
								annotationDialog.annotationID,
								annotationEditor.getText(),
								annotationEditor.getContent()
							));
							
							annotationDialog.hide();
						}
					}
				]);
			}
			return this.__annotationDialog;			
		}		
	});
})(jQuery);